<?php
declare(strict_types=1);

namespace app\logic\api\admin\system;

use think\facade\Db;
use app\logic\api\ApiBaseLogic;
use app\model\api\admin\system\Role;
use app\library\api\admin\Auth;


class RoleLogic extends ApiBaseLogic
{
    public function __construct()
    {
        $this->model = new Role();
    }

    /**
     * 更新角色的数据权限范围
     */
    public function setDataScope($data): array
    {
        Db::startTrans();
        try {
            $role = Role::find($data['id']);
            if (!$role) {
                return $this->fail('角色不存在');
            }

            $count_changed = [
                'ALL' => 0, // "全部数据"数据权限-子级被改动数
                'CUSTOM' => 0, // "自定义"数据权限-子级被改动数
            ];

            $scopeTypeOld = $role['data_scope']['type'];
            $scopeType = $data['data_scope']['type'];

            // 检查是否是超级管理员角色
            $auth = Auth::instance();
            if (!is_super_admin()) {
                // 检查自己是否有对应的数据权限来设置角色的数据权限
                // if (!$auth->hasDataScope(request()->x_token_user['id'], $scopeType)) {
                //     return $this->fail('您不拥有此类数据权限,不能设置,请联系管理员');
                // }

                // 只验证下"全部" 其他的暂不验证
                if ($scopeType == Auth::DATA_SCOPE['ALL'][0]) { // 全部数据 相关
                    if (!$auth->hasDataScope(request()->x_token_user['id'], Auth::DATA_SCOPE['ALL'][0])) {
                        return $this->fail('您不拥有此类数据权限,不能设置,请联系管理员');
                    }
                }
            }

            //region 处理数据权限变化对下级的影响，目前只处理了"全部数据"和"自定义"的权限变化
            if ($scopeType == Auth::DATA_SCOPE['CUSTOM'][0]) { // 自定义 相关
                $userScope = $auth->getDataScope(request()->x_token_user['id']);
                $customDepts = $data['data_scope']['custom'] ?? [];

                if (!$auth->hasDataScope(request()->x_token_user['id'], Auth::DATA_SCOPE['ALL'][0])) {
                    // 检查设置的部门是否在用户的数据范围内
                    foreach ($customDepts as $deptId) {
                        if (!in_array($deptId, $userScope[Auth::DATA_SCOPE['DEPT'][0]])) {
                            return $this->fail('您没有权限设置部门ID: ' . $deptId);
                        }
                    }
                }

                // 如果自定义的部门减少了,需要检查下级角色是否有权限设置这些部门
                $oldCustomDepts = $role->data_scope['custom'] ?? [];
                $removedDepts = array_diff($oldCustomDepts, $customDepts);

                if (!empty($removedDepts)) {
                    // 获取所有下级角色
                    $oldPath = $role->parent_ids ? $role->parent_ids . ',' . $role->id : $role->id;
                    $children = Role::where('parent_ids', 'like', $oldPath . '%')->select();

                    foreach ($children as $child) {
                        if ($child->data_scope['type'] == Auth::DATA_SCOPE['CUSTOM'][0]) {
                            $childCustomDepts = $child->data_scope['custom'] ?? [];
                            // 移除下级角色中不再有权限的部门
                            $newChildDepts = array_diff($childCustomDepts, $removedDepts);

                            if (count($newChildDepts) !== count($childCustomDepts)) {
                                $dataScope = $child->data_scope;
                                $dataScope['custom'] = array_values($newChildDepts);
                                $child->data_scope = $dataScope;
                                $child->save();
                                $count_changed['CUSTOM']++;
                            }
                        }
                    }
                }
            }

            if ($scopeType < $scopeTypeOld) { // 如果降级了
                // 降级了 + 原来是全部数据: 降级下级角色中是全部数据权限的角色。全部数据 相关
                if ($scopeTypeOld == Auth::DATA_SCOPE['ALL'][0]) {
                    $oldPath = $role->parent_ids ? $role->parent_ids . ',' . $role->id : $role->id;
                    $children = Role::where('parent_ids', 'like', $oldPath . '%')->select();

                    foreach ($children as $child) {
                        $childScopeType = $child->data_scope['type'];
                        if ($childScopeType == $scopeTypeOld) {
                            // 子角色权限需要降级
                            $child->data_scope = $data['data_scope'];
                            $child->save();
                            $count_changed['ALL']++;
                        }
                    }
                }
            }
            //endregion

            // 更新data_scope字段
            $role->data_scope = $data['data_scope'];
            $role->save();

            // 清理缓存-模型事件中已处理

            //region 拼装提示信息
            $append_msg = '';
            if ($count_changed['ALL'] > 0) {
                $append_msg .= ' 自动同步' . $count_changed['ALL'] . '个(全部)下级角色';
            }
            if ($count_changed['CUSTOM'] > 0) {
                $append_msg .= ' 影响' . $count_changed['CUSTOM'] . '个(自定义)下级角色';
            }
            //endregion


            Db::commit(); // 提交事务
            return $this->ok('设置数据权限成功' . $append_msg);
        } catch (\Exception $e) {
            Db::rollback();
            throw $e;
        }
    }

    /**
     * 更新角色的菜单权限
     */
    public function setRules($data): array
    {
        Db::startTrans();
        try {
            $role = Role::find($data['id']);
            if (!$role) {
                return $this->fail('角色不存在');
            }

            // 获取当前用户的权限列表
            $auth = Auth::instance();
            $currentUserRules = $auth->getRuleIds(request()->x_token_user['id']);

            // 直接过滤掉当前用户没有的权限，也不能设置进--或者在验证器中验证报错提示
            $filteredRules = array_intersect(explode(',', $data['rules']), $currentUserRules);

            // 上级角色没有的权限,子角色中也要没有
            $parentRole = Role::find($role->parent_id);
            if ($parentRole) {
                $parentRules = explode(',', $parentRole->rules);
                $filteredRules = array_intersect($filteredRules, $parentRules);
            }

            // 获取角色原有的权限
            $oldRules = explode(',', $role->rules);

            // 计算移除的权限
            $removedRules = array_diff($oldRules, $filteredRules);

            // 更新角色的菜单权限
            $role->rules = implode(',', $filteredRules);
            $role->save();

            // 处理下级角色的权限
            $oldPath = $role->parent_ids ? $role->parent_ids . ',' . $role->id : $role->id;
            $children = Role::where('parent_ids', 'like', $oldPath . '%')->select();

            foreach ($children as $child) {
                // 移除下级角色中被移除的权限
                $childRules = explode(',', $child->rules);
                $newChildRules = array_diff($childRules, $removedRules);

                // 父角色中没有的权限,子角色中也要没有
                $newChildRules = array_intersect($newChildRules, $filteredRules);

                if ($childRules !== $newChildRules) {
                    $child->rules = implode(',', array_values($newChildRules));
                    $child->save();
                }
            }

            // 清理缓存
            $auth->clearCache(null, [], [
                'CACHE_AUTH_GROUP_TAG',
                'CACHE_AUTH_MENU_TAG',
                'CACHE_AUTH_LIST_TAG',
            ]);

            Db::commit(); // 提交事务
            return $this->ok('设置菜单权限成功');
        } catch (\Exception $e) {
            Db::rollback();
            throw $e;
        }
    }
}
